package handler

import (
	"net/http"
	"os"
	"path/filepath"
	"sort"
	"strings"

	"github.com/gin-gonic/gin"
	"github.com/sirupsen/logrus"
	"markedit/internal/model"
)

// FileSystemHandler 处理文件系统相关请求
type FileSystemHandler struct {
	logger *logrus.Logger
}

// NewFileSystemHandler 创建新的文件系统处理器
func NewFileSystemHandler(logger *logrus.Logger) *FileSystemHandler {
	return &FileSystemHandler{
		logger: logger,
	}
}

// FileInfo 文件信息结构
type FileInfo struct {
	Name     string     `json:"name"`
	Path     string     `json:"path"`
	Type     string     `json:"type"` // "file" 或 "directory"
	Size     int64      `json:"size"`
	Children []FileInfo `json:"children,omitempty"`
	IsMarkdown bool     `json:"is_markdown"`
}

// GetDirectoryTree 获取目录树
// @Summary 获取目录树
// @Description 获取指定目录的文件树结构
// @Tags FileSystem
// @Accept json
// @Produce json
// @Param path query string false "目录路径，默认为当前工作目录"
// @Param depth query int false "遍历深度，默认为3"
// @Success 200 {object} model.APIResponse
// @Failure 400 {object} model.ErrorResponse
// @Router /api/filesystem/tree [get]
func (h *FileSystemHandler) GetDirectoryTree(c *gin.Context) {
	// 获取参数
	dirPath := c.Query("path")
	if dirPath == "" {
		var err error
		dirPath, err = os.Getwd()
		if err != nil {
			h.logger.Errorf("Failed to get current directory: %v", err)
			c.JSON(http.StatusInternalServerError, model.ErrorResponse{
				Error:   "Failed to get current directory",
				Message: err.Error(),
			})
			return
		}
	}

	// 验证路径安全性
	absPath, err := filepath.Abs(dirPath)
	if err != nil {
		h.logger.Errorf("Invalid path: %v", err)
		c.JSON(http.StatusBadRequest, model.ErrorResponse{
			Error:   "Invalid path",
			Message: err.Error(),
		})
		return
	}

	// 检查路径是否存在
	if _, err := os.Stat(absPath); os.IsNotExist(err) {
		h.logger.Errorf("Path does not exist: %s", absPath)
		c.JSON(http.StatusNotFound, model.ErrorResponse{
			Error:   "Path not found",
			Message: "The specified path does not exist",
		})
		return
	}

	// 构建目录树
	tree, err := h.buildDirectoryTree(absPath, 3) // 默认深度为3
	if err != nil {
		h.logger.Errorf("Failed to build directory tree: %v", err)
		c.JSON(http.StatusInternalServerError, model.ErrorResponse{
			Error:   "Failed to build directory tree",
			Message: err.Error(),
		})
		return
	}

	c.JSON(http.StatusOK, model.APIResponse{
		Success: true,
		Data:    tree,
		Message: "Directory tree retrieved successfully",
	})
}

// buildDirectoryTree 递归构建目录树
func (h *FileSystemHandler) buildDirectoryTree(dirPath string, maxDepth int) (FileInfo, error) {
	info, err := os.Stat(dirPath)
	if err != nil {
		return FileInfo{}, err
	}

	fileInfo := FileInfo{
		Name: info.Name(),
		Path: dirPath,
		Size: info.Size(),
	}

	if info.IsDir() {
		fileInfo.Type = "directory"
		
		// 如果还有深度，继续遍历子目录
		if maxDepth > 0 {
			children, err := h.getDirectoryChildren(dirPath, maxDepth-1)
			if err != nil {
				h.logger.Warnf("Failed to read directory children: %v", err)
				// 不返回错误，只是没有子项
			} else {
				fileInfo.Children = children
			}
		}
	} else {
		fileInfo.Type = "file"
		fileInfo.IsMarkdown = h.isMarkdownFile(fileInfo.Name)
	}

	return fileInfo, nil
}

// getDirectoryChildren 获取目录的子项
func (h *FileSystemHandler) getDirectoryChildren(dirPath string, maxDepth int) ([]FileInfo, error) {
	entries, err := os.ReadDir(dirPath)
	if err != nil {
		return nil, err
	}

	var children []FileInfo
	for _, entry := range entries {
		// 跳过隐藏文件和特殊目录
		if strings.HasPrefix(entry.Name(), ".") {
			continue
		}

		childPath := filepath.Join(dirPath, entry.Name())
		childInfo, err := h.buildDirectoryTree(childPath, maxDepth)
		if err != nil {
			h.logger.Warnf("Failed to process child item %s: %v", childPath, err)
			continue
		}

		children = append(children, childInfo)
	}

	// 排序：目录在前，文件在后，同类型按名称排序
	sort.Slice(children, func(i, j int) bool {
		if children[i].Type != children[j].Type {
			return children[i].Type == "directory"
		}
		return strings.ToLower(children[i].Name) < strings.ToLower(children[j].Name)
	})

	return children, nil
}

// isMarkdownFile 判断是否为Markdown文件
func (h *FileSystemHandler) isMarkdownFile(filename string) bool {
	ext := strings.ToLower(filepath.Ext(filename))
	return ext == ".md" || ext == ".markdown"
}

// ReadFile 读取文件内容
// @Summary 读取文件内容
// @Description 读取指定文件的内容
// @Tags FileSystem
// @Accept json
// @Produce json
// @Param path query string true "文件路径"
// @Success 200 {object} model.APIResponse
// @Failure 400 {object} model.ErrorResponse
// @Router /api/filesystem/read [get]
func (h *FileSystemHandler) ReadFile(c *gin.Context) {
	filePath := c.Query("path")
	if filePath == "" {
		c.JSON(http.StatusBadRequest, model.ErrorResponse{
			Error:   "Missing file path",
			Message: "File path is required",
		})
		return
	}

	// 验证路径安全性
	absPath, err := filepath.Abs(filePath)
	if err != nil {
		h.logger.Errorf("Invalid file path: %v", err)
		c.JSON(http.StatusBadRequest, model.ErrorResponse{
			Error:   "Invalid file path",
			Message: err.Error(),
		})
		return
	}

	// 检查文件是否存在
	info, err := os.Stat(absPath)
	if os.IsNotExist(err) {
		c.JSON(http.StatusNotFound, model.ErrorResponse{
			Error:   "File not found",
			Message: "The specified file does not exist",
		})
		return
	}

	// 检查是否为文件（不是目录）
	if info.IsDir() {
		c.JSON(http.StatusBadRequest, model.ErrorResponse{
			Error:   "Path is directory",
			Message: "Cannot read directory as file",
		})
		return
	}

	// 读取文件内容
	content, err := os.ReadFile(absPath)
	if err != nil {
		h.logger.Errorf("Failed to read file: %v", err)
		c.JSON(http.StatusInternalServerError, model.ErrorResponse{
			Error:   "Failed to read file",
			Message: err.Error(),
		})
		return
	}

	c.JSON(http.StatusOK, model.APIResponse{
		Success: true,
		Data: map[string]interface{}{
			"path":    absPath,
			"content": string(content),
			"size":    len(content),
		},
		Message: "File read successfully",
	})
}